package com.mikufufu.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mikufufu.blog.model.entity.Role;
import com.mikufufu.blog.model.entity.RolePermission;
import com.mikufufu.blog.model.vo.admin.PermissionVO;
import com.mikufufu.blog.model.vo.admin.PermissionRoleListVO;
import com.mikufufu.blog.security.enums.RoleCode;
import com.mikufufu.blog.security.handler.FilterInvocationSecurityMetadataSourceImpl;
import com.mikufufu.blog.service.RolePermissionService;
import com.mikufufu.blog.service.RoleService;
import com.mikufufu.blog.utils.SpringUtils;
import com.mikufufu.blog.utils.StringUtils;
import com.mikufufu.blog.mapper.PermissionMapper;
import com.mikufufu.blog.model.entity.Permission;
import com.mikufufu.blog.service.PermissionService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 权限表 服务实现类
 * 
 */
@Slf4j
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService {

    @Autowired
    private RolePermissionService rolePermissionService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    // 定义目标包名
    @Value("${client-api.target-package}")
    String targetPackage;

    @Override
    public Set<Permission> getPermissionSet(Integer roleId) {
        if (StringUtils.isEmpty(roleId)) {
            throw new RuntimeException("roleId不能为空");
        }
        return new HashSet<>(baseMapper.getPermission(roleId));
    }

    @Override
    public List<PermissionRoleListVO> getPermissionRoleList() {
        return baseMapper.getPermissionRoleList();
    }

    @Override
    public Boolean addRolePermission(Integer roleId, Integer permissionId) {
        Permission permission = this.getById(permissionId);
        if (StringUtils.isEmpty(permission)){
            throw new RuntimeException("权限不存在");
        }
        RolePermission rolePermission = new RolePermission();
        rolePermission.setRoleId(roleId);
        rolePermission.setPermissionId(permissionId);
        if(rolePermissionService.save(rolePermission)){
            // 清空权限系统缓存
            cleanRolePermission();
            return true;
        }
        return false;
    }

    /**
     * 为所有控制器方法添加权限信息。
     * 此方法会遍历所有控制器方法，根据方法上的注解（如@ApiOperation和@PreAuthorize）来构建Permission对象，
     * 然后将这些Permission对象批量保存到数据库中。如果方法上有@ApiOperation注解，则会使用其value值作为权限名称；
     * 如果方法上有@PreAuthorize注解，则会截取其value值中特定的字符串作为权限标识。
     *
     * @return 返回批量保存权限信息是否成功的布尔值。
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean addAllControllerPermission() {
        List<Permission> permissionList = new ArrayList<>();
        List<Permission> existingPermissions = this.list();
        // 创建权限标识映射
        Map<String, Permission> existingPermissionMap = existingPermissions.stream()
                .collect(Collectors.toMap(
                        p -> p.getPath() + ":" + p.getMethod().toUpperCase(),
                        Function.identity()
                ));
        // 创建权限路径集合
        Set<String> permissionPaths = new HashSet<>();
        // 获取所有映射的处理方法
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
        // 遍历处理方法，解析URL和请求方法，并检查是否有@Anonymous注解
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()){
            RequestMappingInfo k = entry.getKey();
            HandlerMethod v = entry.getValue();
            Permission permission = new Permission();
            PatternsRequestCondition patternsRequestCondition = k.getPatternsCondition();
            if (patternsRequestCondition == null){
                continue;
            }
            // 解析URL
            patternsRequestCondition.getPatterns().forEach(permission::setPath);
            RequestMethodsRequestCondition methodsCondition = k.getMethodsCondition();
            // 解析请求方法
            methodsCondition.getMethods().forEach(method -> permission.setMethod(method.name()));
            if (StringUtils.isEmpty(permission.getPath()) || StringUtils.isEmpty(permission.getMethod())){
                continue;
            }
            Method method = v.getMethod();
            if (method.isAnnotationPresent(ApiOperation.class)){
                ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
                permission.setName(apiOperation.value());
            }
            if (method.isAnnotationPresent(PreAuthorize.class)){
                PreAuthorize preAuthorize = method.getAnnotation(PreAuthorize.class);
                permission.setSign(preAuthorize.value().replace("@ss.hasPermission('", "").replace("')", ""));
            }
            permission.setStatus(0);
            if (permission.getMethod() != null){
                // 设置复合键
                String compositeKey = permission.getPath() + ":" + permission.getMethod().toUpperCase();
                if (!existingPermissionMap.containsKey(compositeKey)){
                    permissionList.add(permission);
                }
                permissionPaths.add(compositeKey);
            }
        }
        // 删除多余的权限信息
        List<Integer> removePermissions = existingPermissions.stream()
                .filter(p -> !permissionPaths.contains(p.getPath() + ":" + p.getMethod().toUpperCase()))
                .map(Permission::getId)
                .collect(Collectors.toList());
        if (!removePermissions.isEmpty()){
            log.info("删除多余的权限信息：{}", removePermissions);
            removeByIds(removePermissions);
        }
        if (permissionList.isEmpty()){
            return true;
        }
        // 批量保存权限信息
        log.info("批量保存权限信息：{}", permissionList);
        return saveBatch(permissionList);
    }

    @Override
    public Boolean setAllPermission(Integer roleId) {
        // 清空权限系统缓存
        cleanRolePermission();
        return baseMapper.setAllPermission(roleId) > 0;
    }

    @Override
    public Boolean cleanRolePermission() {
        try {
            SpringUtils.getBean(FilterInvocationSecurityMetadataSourceImpl.class).clearDataSource();
        }catch (Exception e){
            log.error("清空权限系统缓存失败", e);
            return false;
        }
        return true;
    }

    @Override
    public List<PermissionVO> getPermissionByRole(Integer roleId) {
        return baseMapper.getPermissionByRole(roleId);
    }

    // 实现获取controller下的web下的接口
    @Override
    public Boolean grantAnonymousPermission() {
        // 获取所有映射的处理方法
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
//        List<Permission> webPermissions = new ArrayList<>();
        List<String> webPermissionPaths = new ArrayList<>();
        Map<String,Permission> permissionMap = this.list().stream().collect(Collectors.toMap(Permission::getPath, p -> p));
    
        // 遍历处理方法，提取 web 接口
        handlerMethods.forEach((requestMappingInfo, handlerMethod) -> {
            // 检查处理方法是否属于目标包
            Class<?> beanType = handlerMethod.getBeanType();
            if (beanType.getPackage().getName().startsWith(targetPackage)) {
                PatternsRequestCondition patternsCondition = requestMappingInfo.getPatternsCondition();
                if (patternsCondition != null) {
                    patternsCondition.getPatterns().forEach(pattern -> {
                        // 将权限信息添加到列表中
                        log.info("web权限列表：{}",pattern);
                        webPermissionPaths.add(pattern);
                    });
                }
            }
        });

//        log.info("web权限列表：{}",webPermissions);

        try {
            Role role = roleService.getOne(new LambdaQueryWrapper<Role>().eq(Role::getRoleCode, RoleCode.ROLE_VISITOR.getCode()));
            Integer roleId = role.getId();

            // 这里可以将 webPermissions 保存到数据库或进行其他处理
            List<RolePermission> rolePermissions = webPermissionPaths.stream().filter(path -> permissionMap.containsKey(path) && permissionMap.get(path) != null)
                    .map(path -> {
                        RolePermission rolePermission = new RolePermission();
                        rolePermission.setRoleId(roleId);
                        rolePermission.setPermissionId(permissionMap.get(path).getId());
                        return rolePermission;
                    }).collect(Collectors.toList());
            // 删除该角色下的所有权限
            rolePermissionService.remove(new LambdaQueryWrapper<RolePermission>().eq(RolePermission::getRoleId, roleId));
            rolePermissionService.saveBatch(rolePermissions);
            cleanRolePermission();
        } catch (Exception e) {
            log.error("保存web权限失败", e);
            return false;
        }
    
        return true; // 返回操作成功的布尔值
    }


}
